package com.lzx.hbh_system.shiro;

import com.lzx.hbh_system.util.staitcParma.ResultEnum;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.authc.LogoutFilter;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

/**
 * eq:只能在shiro启用的情况下有效。由于我关闭了shiro的session功能，使用了JWT结合验证前后端登陆状态交互。所以用使用下面注释的第一种方案暂时解决用户退出问题
 * 自定义登出过滤器，返回指定URL进行跳转或者返回JSON给前端进行跳转
 * 在shirocofiger配置对应的过滤链，对应的url地址直接访问就实现推出登陆功能，不需要实现controller
 */
@Slf4j
public class UserLogoutFilter extends LogoutFilter {//---弃用
    @Override
    protected boolean preHandle(ServletRequest request, ServletResponse response) throws Exception {
        Subject subject = getSubject(request,response);
        /*
        *
        * 由于使用了JWT 用作前后端用户信息交互，所以关闭了shiro自带的session，由于subject的初始化是使用到了session所以，导致session一直为空
        * 解决方案如下 ：参考：https://www.zhihu.com/question/397457110
        *
        * 1.客户端清除 token登出时在浏览器或者 APP 客户端清除 token。
        * 这种方法比较简单，无需后端操作。但不经过服务器验证的客户端清除 token 操作会造成登出后使用原 token 仍有访问权限的问题，
        * 针对该问题，token 的过期时间可以设置尽可能短，以减少原 token 的有效的时间。
        *
        * 2.白名单在 Redis 维护有效的 token，在 token 生成后就存入 Redis，登出时从 Redis 删除该 token。
        * 在验证  token 之前先查询白名单中是否有该 token，如果有则表明是有效的，然后进入解析 token 的逻辑。
        * 有点像有状态的 session 的味道了。为了避免白名单不断变大，可以按照 jwt 中的过期时间来设置存入 Redis 的 token 的过期时间
        *
        * 3.黑名单在 Redis 维护登出的无效 token，在验证 token 之前先查询黑名单中是否有该 token，如果没有表明是有效的，然后进入解析 token 的逻辑。
        * 为了避免黑名单不断变大， 可以按照 jwt 中的过期时间来设置存入 Redis 的 token 的过期时间。一般黑名单会比白名单占用的内存小。
        *
        * */
        System.out.println("subject_isAuthenticated"+subject.isAuthenticated());
        subject.logout();
        request.setCharacterEncoding("utf-8");
        String RedirectURl = "/error/"+ ResultEnum.NO_LOGIN.getMsg()+"，没有退出这一说！"+"/"+ResultEnum.NO_LOGIN.getCode();
        issueRedirect(request,response,RedirectURl);
        return false;
    }
}
